"""
@作者: sipeiliu@163.com
@功能: 电脑端，发送更新代码
"""

import socket
import threading
import zipfile
import os
import json
import time
import sys

'''服务端类'''
class ServerSocket():
    '''初始化socket与文件'''
    def __init__(self, ref_ip):
        # 接受来自gui.py的ref_ip
        self.ref_ip = ref_ip
        # 数据发送速度控制，太大速度慢，太小易丢包
        self.send_rate = 0.03
        # 创建udp电脑端套接字
        self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        # 绑定IP地址和端口号，空字符串默认为本机IP
        self.server_socket.bind(('', 8888))
        # 项目地址
        self.file_path = "/opt/fs_ws"
        # 压缩地址
        self.zip_path = "/opt/fs_ws.zip"

    '''压缩项目文件'''
    def zip_file(self):
        # 创建压缩对象
        zip = zipfile.ZipFile(self.zip_path, "w", zipfile.ZIP_DEFLATED)
        # 深度优先遍历项目文件
        for root, dirs, files in os.walk(self.file_path):
            root_relpath = os.path.relpath(root, "/opt")
            for file in files:
                zip.write(os.path.join(root, file), os.path.join(root_relpath, file))
        zip.close()
        print("压缩项目文件成功...")


    '''发送文件给树莓派'''
    def send_file(self):
        # 文件的大小与日期
        header_data = {
            'size': os.stat(self.zip_path).st_size, # 大小
            'date': time.strftime('%Y-%m-%d %X', time.localtime()), # 日期
            }
        print("开始发送文件包...")
        print(header_data['date'])
        print('\n')
        # 遍历更新字典的树莓派
        for ref, ip in self.ref_ip.items():
            # 创建子线程，发送数据(线程名、回调函数、参数)
            sub_thread = threading.Thread(target = self.handle, args = (header_data, ip))
            # 启动子线程
            sub_thread.start()         

    '''发送数据'''
    def handle(self, header_data, ip):
        # 发送文件大小与时间
        self.server_socket.sendto(json.dumps(header_data).encode(), (ip, 8888))
        # 发送文件包
        with open(self.zip_path, 'rb') as f:
            send_size = 0
            # 根据文件字节大小判断是否发送完毕
            while send_size < header_data['size']:
                connect = f.read(1024*32)
                self.server_socket.sendto(connect, (ip, 8888))
                # 计算已发送的字节大小，TODO：getsizeof获取的大小比真实值大33字节？
                send_size += sys.getsizeof(connect) - 33
                # 控制发送速度
                time.sleep(self.send_rate)
        
def run(args = None):
    # 实例化服务端对象
    server = ServerSocket()
    # 压缩项目文件
    server.zip_file()
    # 发送项目文件
    server.send_file()   

if __name__ == '__main__':
    run()